//
//Justin Swinney
//CPE302 DA6
// 1. Write an AVR C program to control the speed of the Stepper Motor using a
//potentiometer connected to any of the analog-in port.
//
// 2. Write an AVR C program to control the position of the Servo Motor using a
//potentiometer connected to any of the analog-in port. When pot value is 0 the servo is
//at position 0 deg. and when pot value is max (approx. 5V) the servo is at position 180
//deg.
//

//////////////////////////////////////////////////////////////////////////////////////////////////////////////
//Stepper Motor Code:
 #define F_CPU 8000000UL //XTAL = 8MHZ
#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>

unsigned char a_high; // variable to hold high ADC value
unsigned char a_low; // variable to hold low ADC value
int delay = 50;	// determines motor speed
int time = 0; // pseudo-time variable

//timer 1 initialization
void timer1_init(int value)
{
	TCCR1A = 0x00;
	TCCR1B = 0x05;
	TCNT1H = 0xF0;
	TCNT1L = 0xBD;
	if(value)
	TIFR1 = 0x01; //clears TOV1
}

//adc setup
void ADC_init()
{
	ADCSRA = 0xDF; //128 prescaler
	ADCSRB = 0x06; //timer1 overflow
	ADMUX = 0xC0; //ADC0, AREF
}

int main()
{
	sei();	// enable interrupts
	ADC_init();	// initialize ADC
	timer1_init(0);	// initialize timer 1
	
	DDRC = 0x00;	// PORTC input
	DDRB = 0xFF;	// PORTD output
	while(1)	// spin motor
	{
		PORTB = 0X66;
		_delay_ms(delay);
		PORTB = 0xCC;
		_delay_ms(delay);
		PORTB = 0x99;
		_delay_ms(delay);
		PORTB = 0x33;
		_delay_ms(delay);
	}
	return 0;
}

//interrupt service routine function
ISR(ADC_vect)
{
	ADCSRA = 0xBF; //clear AD complete flag
	timer1_init(1); // reset timer1
	time++; //count pseudo-time
	
	//Read ADC value
	//NOTE: Even though only ADC is being used,
	//ADCH must be read for proper operation.
	a_low = ADCL;
	a_high = ADCH;
	
	if(time == 4) //once count is 5, 2 second(s) has passed
	{
		time = 0; //reset pseudo-time
		delay = a_low; // update delay
	}
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////


//////////////////////////////////////////////////////////////////////////////////////////////////////////////
//Servo Motor Code:
#define F_CPU 8000000UL
#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>

//Variables
unsigned char a_high; // variable to hold high ADC value
unsigned char a_low; // variable to hold low ADC value
int time2 = 0; // pseudo-time variable

//timer 0 initialization
void timer0_init(int value_2)
{
	TCCR0A = 0x00;
	TCCR0B = 0x05; // Normal mode, 1024 prescaler
	if(value_2)
	{
		TIFR0 = 0x01; //clears TOV0
	}
}

//timer 1 initialization
void timer1_init(int value)
{
	TCCR1A = 0xA2;
	TCCR1B = 0x1A; // Phase Correct PWM, inverted, N = 8
	ICR1 = 20000; // Set 50 Hz PWM
	OCR1A = 0; // initial 0% duty cycle
	OCR1B = 0; // initial 0% duty cycle
	if(value)
	TIFR1 = 0x01; //clears TOV1
}

//adc setup
void ADC_init()
{
	ADCSRA = 0xDF; //128 prescaler
	ADCSRB = 0x06; //timer1 overflow
	ADMUX = 0xC0; //ADC0, AREF
}

int main()
{
	sei(); // enable interrupts
	DDRB = 0xFF; //PB3 as output
	ADC_init();	// initialize ADC
	timer0_init(0);	// initialize timer0
	timer1_init(0);	// initialize timer1

	while (1) // wait here for ADC interrupt
	{
	}
	return 0;
}

//interrupt service routine function
ISR(ADC_vect)
{
	ADCSRA = 0xBF; //clear AD complete flag
	timer0_init(1); // reset timer1
	time2++; //count pseudo-time
	a_low = ADCL;
	a_high = ADCH;
	
	OCR1B = a_high*2; // scale to useful value
	OCR1B = (OCR1B<<8); // shift high bits to OCR1BH
	OCR1B = OCR1B | (a_low*2); // scale and add remaining low bits to OCR1L
}
	//////////////////////////////////////////////////////////////////////////////////////////////////////////////.
